#include "Cmaid_Gtest.h"

TEST_P(Cmaid_Map_Gtest, count_add)
{
	int i;

	for (i = 0; i < dataCount(); i++)
	{
		ASSERT_EQ(i, cmaid_container_count(map));
		cmaid_map_set(map, valueAt(i), keyAt(i));
	}
}

TEST_P(Cmaid_Map_Gtest, count_add_same)
{
	int i;

	ASSERT_EQ(0, cmaid_container_count(map));
	cmaid_map_set(map, keyAt(0), valueAt(0));
	ASSERT_EQ(1, cmaid_container_count(map));

	for (i = 0; i < 1000; i++)
	{
		ASSERT_EQ(1, cmaid_container_count(map));
		cmaid_map_set(map, keyAt(0), valueAt(0));
	}
}

TEST_P(Cmaid_Map_Gtest, set)
{
	int i;

	for (i = 0; i < dataCount(); i++)
	{
		void *data;

		data = cmaid_map_set(map, keyAt(i), valueAt(i));
		/* this needs to be the key value */
		ASSERT_TRUE(NULL != data);
		ASSERT_KEY_EQ(keyAt(i), data);
		if (keyIsPointerType())
			ASSERT_EQ(keyAt(i), data);
		else
			ASSERT_NE(keyAt(i), data);

		data = cmaid_map_get(map, keyAt(i));
		/* and here we get the value */
		ASSERT_TRUE(NULL != data);
		ASSERT_VALUE_EQ(valueAt(i), data);
		if (valueIsPointerType())
			ASSERT_EQ(valueAt(i), data);
		else
			ASSERT_NE(valueAt(i), data);
	}
}

TEST_P(Cmaid_Map_Gtest, remove)
{
	int i;

	for (i = 0; i < dataCount(); i++)
		cmaid_map_set(map, keyAt(i), valueAt(i));
	
	for (i = 0; i < dataCount(); i++)
	{
		void *name = cmaid_map_get(map, keyAt(i));

		ASSERT_TRUE(NULL != name);
		ASSERT_VALUE_EQ(valueAt(i), name);
		cmaid_map_remove(map, keyAt(i));
		ASSERT_EQ(dataCount() - i - 1, cmaid_container_count(map));
		/* this name shouldn't be in the map anymore */
		cmaid_map_remove(map, keyAt(i));
		/* ergo the container count should be the same as before */
		ASSERT_EQ(dataCount() - i - 1, cmaid_container_count(map));
	}
}

TEST_P(Cmaid_Map_Gtest, remove_inverse)
{
	int i;

	fill();
	
	for (i = dataCount() - 1; i >= 0; i--)
	{
		void *name = cmaid_map_get(map, keyAt(i));
		ASSERT_KEY_EQ(valueAt(i), name);
		cmaid_map_remove(map, keyAt(i));
		ASSERT_EQ(i, cmaid_container_count(map));
		/* this name shouldn't be in the map anymore */
		cmaid_map_remove(map, keyAt(i));
		/* ergo the container count should be the same as before */
		ASSERT_EQ(i, cmaid_container_count(map));
	}
}

TEST_P(Cmaid_Map_Gtest, clear)
{
	int i;

	/* the container is supposed to be empty */
	ASSERT_EQ(0, cmaid_container_count(map));
	/* first clear an empty map, I know that seems to be non-sense
	 * but maybe we trigger a hidden bug */
	cmaid_container_clear(map);
	ASSERT_EQ(0, cmaid_container_count(map));

	fill();
	/* and now do the same with a filled map */
	cmaid_container_clear(map);
	ASSERT_EQ(0, cmaid_container_count(map));

	/* let's see if we find a name in it */
	for (i = 0; i < dataCount(); i++)
	{
		void *data;
		data = cmaid_map_get(map, keyAt(i));
		ASSERT_TRUE(NULL == data);
	}
}

TEST_P(Cmaid_Map_Gtest, dump)
{
	Cmaid_Iter iter __CMAID_CHECKED_ITER__;
	FILE *file;
	void *data;
	int size;

	/* Of course we cannot test the output of dump here without
	 * writing an disproportional difficult parser. So we only test
	 * it to see if it segfault and do some alibi tests */
	fill();
	cmaid_container_iter_attach(map, &iter);
	data = cmaid_iter_index_goto(&iter, 3);
	size = cmaid_container_count(map);

	file = tmpfile();
	cmaid_container_dump(map, file);
	fclose(file);

	ASSERT_EQ(size, cmaid_container_count(map));
	ASSERT_KEY_EQ(data, cmaid_iter_current(&iter));
	ASSERT_EQ(3, cmaid_iter_index_get(&iter));
	
	cmaid_container_iter_detach(map, &iter);
}

TEST_P(Cmaid_Map_Gtest, empty)
{
	int i;

	ASSERT_EQ(0, cmaid_container_count(map));
	/* let's see if we find a name */
	for (i = 0; i < dataCount(); i++)
	{
		void *data;
		data = cmaid_map_get(map, keyAt(i));
		ASSERT_TRUE(NULL == data);
	}
}

TEST_P(Cmaid_Map_Gtest, iter_value_attach)
{
	Cmaid_Iter it_v, it_k;

	cmaid_map_value_iter_attach(map, &it_v);
	cmaid_container_iter_attach(map, &it_k);
	ASSERT_EQ(-1, cmaid_iter_index_get(&it_v));
	ASSERT_EQ(NULL, cmaid_iter_current(&it_v));
	ASSERT_EQ(-1, cmaid_iter_index_get(&it_k));
	ASSERT_EQ(NULL, cmaid_iter_current(&it_k));
	cmaid_container_iter_detach(map, &it_v);
	cmaid_container_iter_detach(map, &it_k);

	/* and know do the same but fill the iter in the mean time */	
	cmaid_map_value_iter_attach(map, &it_v);
	cmaid_container_iter_attach(map, &it_k);
	fill();
	ASSERT_EQ(-1, cmaid_iter_index_get(&it_v));
	ASSERT_EQ(NULL, cmaid_iter_current(&it_v));
	ASSERT_EQ(-1, cmaid_iter_index_get(&it_k));
	ASSERT_EQ(NULL, cmaid_iter_current(&it_k));
	cmaid_container_iter_detach(map, &it_v);
	cmaid_container_iter_detach(map, &it_k);
}

TEST_P(Cmaid_Map_Gtest, iter_value_next)
{
	Cmaid_Iter it_val, it_key;
	void *name;

	fill();

	cmaid_container_iter_attach(map, &it_key);
	cmaid_map_value_iter_attach(map, &it_val);

	while ((name = cmaid_iter_next(&it_key)))
	{
		void *first_name;
		void *ret;

		first_name = cmaid_iter_next(&it_val);
		ASSERT_TRUE(NULL != first_name);

		ret = cmaid_map_get(map, name);
		ASSERT_TRUE(NULL != ret);
		ASSERT_VALUE_EQ(ret, first_name);
	}

	cmaid_container_iter_detach(map, &it_key);
	cmaid_container_iter_detach(map, &it_val);
}

TEST_P(Cmaid_Map_Gtest, iter_value_previous)
{
	Cmaid_Iter it_val, it_key;
	void *name;

	fill();
	
	cmaid_container_iter_attach(map, &it_key);
	cmaid_map_value_iter_attach(map, &it_val);

	while ((name = cmaid_iter_previous(&it_key)))
	{
		void *first_name;
		void *ret;

		first_name = cmaid_iter_previous(&it_val);
		ASSERT_TRUE(NULL != first_name);

		ret = cmaid_map_get(map, name);
		ASSERT_TRUE(NULL != ret);
		ASSERT_VALUE_EQ(ret, first_name);
	}

	cmaid_container_iter_detach(map, &it_key);
	cmaid_container_iter_detach(map, &it_val);
}

TEST_P(Cmaid_Map_Gtest, iter_value_remove)
{
	int index;
	for (index = 0; index < dataCount(); index++)
	{
		Cmaid_Iter it_first, it_last, it;
		void *prev_data;

		fill();

		cmaid_map_value_iter_attach(map, &it_first);
		/* go to the first node */
		cmaid_iter_next(&it_first);
		ASSERT_EQ(0, cmaid_iter_index_get(&it_first));

		cmaid_map_value_iter_attach(map, &it_last);
		cmaid_iter_previous(&it_last);
		ASSERT_EQ(dataCount() - 1, cmaid_iter_index_get(&it_last));

		cmaid_map_value_iter_attach(map, &it);
		prev_data = cmaid_iter_index_goto(&it, index - 1);
		/* next would do the same, but hey, that are unit tests */
		cmaid_iter_index_goto(&it, index);

		/* now remove the index-th node */
		cmaid_iter_remove(&it);
		ASSERT_EQ(index - 1, cmaid_iter_index_get(&it));
		ASSERT_EQ(prev_data, cmaid_iter_current(&it));
		if (index != 0)
			ASSERT_TRUE(NULL != prev_data);
		else
			ASSERT_EQ(NULL, prev_data);

		/* test the first iter */
		if (index != 0)
			/* the index shouldn't have been changed */
			ASSERT_EQ(0, cmaid_iter_index_get(&it_first));
		else
			ASSERT_EQ(-1, cmaid_iter_index_get(&it_first));

		/* test the last iter */
		ASSERT_EQ(dataCount() - 2, cmaid_iter_index_get(&it_last));

		cmaid_container_iter_detach(map, &it_last);
		cmaid_container_iter_detach(map, &it_first);
		cmaid_container_iter_detach(map, &it);

		cmaid_container_clear(map);
	}
}

TEST_P(Cmaid_Map_Gtest, iter_value_remove2)
{
	int index;

	for (index = 0; index < dataCount(); index++)
	{
		Cmaid_Iter it_prev, it_next, it;

		cmaid_map_value_iter_attach(map, &it_prev);
		cmaid_map_value_iter_attach(map, &it_next);
		cmaid_map_value_iter_attach(map, &it);

		fill();

		cmaid_iter_index_goto(&it, index);
		/* move the next iter after the iter */
		cmaid_iter_iter_goto(&it_next, &it);
		cmaid_iter_next(&it_next);

		/* move the prev iter before the iter */
		cmaid_iter_iter_goto(&it_prev, &it);
		cmaid_iter_previous(&it_prev);

		/* now remove the index-th node */
		cmaid_iter_remove(&it);
		ASSERT_EQ(index - 1, cmaid_iter_index_get(&it));
		ASSERT_EQ(cmaid_iter_index_get(&it_prev),
				cmaid_iter_index_get(&it));
		ASSERT_EQ(cmaid_iter_current(&it_prev),
				cmaid_iter_current(&it));

		/* test the next iter */
		if (index != dataCount() - 1)
			ASSERT_EQ(index, cmaid_iter_index_get(&it_next));
		else
			ASSERT_EQ(-1, cmaid_iter_index_get(&it_next));

		ASSERT_EQ(cmaid_iter_current(&it), cmaid_iter_previous(&it_next));

		cmaid_container_iter_detach(map, &it_prev);
		cmaid_container_iter_detach(map, &it_next);
		cmaid_container_iter_detach(map, &it);

		cmaid_container_clear(map);
	}
}

